<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>addEventListener</title>
    <link rel="stylesheet" href="../../styles/normalize.css" />
  </head>
  <body>
    <div>
      <table id="outside1">
        <tr>
          <td id="t11">one</td>
        </tr>
        <tr>
          <td id="t21">two</td>
        </tr>
      </table>
      <table id="outside2">
        <tr>
          <td id="t12">one</td>
        </tr>
        <tr>
          <td id="t22">two</td>
        </tr>
      </table>
      <table id="outside3">
        <tr>
          <td id="t13">one</td>
        </tr>
        <tr>
          <td id="t23">two</td>
        </tr>
      </table>
    </div>
    <div id="box">
      <button id="reset">重置</button>
      <button id="submit">提交</button>
    </div>
    <script>
      /**
       * 相比于 onXYZ 属性绑定来说，它提供了一种更精细的手段来控制 listener 的触发阶段。（即可以选择捕获或者冒泡）
       * 举例 input元素的
       *     click  事件侦听器列表
       *     input  事件侦听器列表
       *     change 事件侦听器列表
       *
       * 当一个 EventListener 在 EventTarget 正在处理事件的时候被注册到 EventTarget 上
       * 它不会被立即触发，但可能在事件流后面的事件触发阶段被触发，例如可能在捕获阶段添加，然后在冒泡阶段被触发。
       *
       * 事件流后面的事件触发阶段
       * 事件捕获阶段 从外向内
       * 事件冒泡阶段 从内向外
       *
       */
      /**
       * addEventListener(type, listener); ==> addEventListener(type, listener, false);
       * addEventListener(type, listener, useCapture);
       *    type 事件类型
       *    listener 必须是一个实现了 EventListener 接口的对象，或者是一个函数
       *    useCapture: 一个布尔值，表示在 DOM 树中注册了 listener 的元素，是否要先于它下面的 EventTarget 调用该 listener
       * addEventListener(type, listener, options);
       *    options = { capture, once, passive, signal  }
       *        once: 表示 listener在添加之后最多只调用一次。如果为true，listener 会在其被调用之后自动移除。
       *        capture: 表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。
       *        passive: 表示 listener 永远不会调用 preventDefault()
       */
      const boxEl = document.getElementById("box");
      const resetEl = document.getElementById("reset");
      const submitEl = document.getElementById("submit");
      const box_click_cb = function (ev) {
        console.log(2);
        console.log(ev);
      };
      const reset_click_cb = function (ev) {
        ev.preventDefault(); // 阻止默认行为，和冒泡没关系
        console.log(ev);
      };
      const submit_click_cb = function (ev) {
        ev.preventDefault(); // 阻止默认行为，和冒泡没关系
        console.log(ev);
      };

      submitEl.addEventListener("click", submit_click_cb);
      resetEl.addEventListener("click", reset_click_cb);
      boxEl.addEventListener("click", box_click_cb, true); // useCapture box_click_cb 先于 reset_click_cb|submit_click_cb

      /**
       * 如何解决老浏览器 第三个参数不支持对象的 兼容性问题
       * 在旧版本的 DOM 的规定中，addEventListener() 的第三个参数是一个布尔值
       */
      /**
       * addEventListener 举例
       */
      // 改变 t2 内容的函数
      function modifyText() {
        const t2 = document.getElementById("t21");
        const isNodeThree = t2.firstChild.nodeValue === "three";
        t2.firstChild.nodeValue = isNodeThree ? "two" : "three";
      }

      /**
       * 添加一个可被移除的监听器
       */
      // 改变 t2 内容的函数
      function modifyText1() {
        const t2 = document.getElementById("t21");
        if (t2.firstChild.nodeValue === "three") {
          t2.firstChild.nodeValue = "two";
        } else {
          t2.firstChild.nodeValue = "three";
          controller.abort(); // 当值变为 "three" 后，移除监听器
        }
      }
      // 为 table 添加可被移除的事件监听器
      const controller = new AbortController();
      const el = document.getElementById("outside1");
      el.addEventListener("click", modifyText1, { signal: controller.signal });

      /**
       * 带有匿名函数的监听器
       */
      // 改变 t2 内容的函数
      function modifyText2(new_text) {
        console.log(new_text);
        const t2 = document.getElementById("t22");
        t2.firstChild.nodeValue = new_text;
      }

      // 用匿名函数为 table 添加事件监听器
      const el2 = document.getElementById("outside2");
      el2.addEventListener(
        "click",
        function () {
          modifyText2("four");
        },
        false
      );

      /**
       * 带有箭头函数的监听器
       */
      // 改变 t2 内容的函数
      function modifyText3(new_text) {
        console.log(new_text);
        var t2 = document.getElementById("t23");
        t2.firstChild.nodeValue = new_text;
      }

      // 用箭头函数为 table 添加事件监听器
      const el3 = document.getElementById("outside3");
      el3.addEventListener(
        "click",
        () => {
          modifyText3("five");
        },
        false
      );
    </script>
  </body>
</html>
